import time
import cv2
import numpy as np
import pytesseract
import win32gui
import win32con
import win32ui
import win32process
import ctypes
from PIL import Image, ImageTk
import tkinter as tk
from tkinter import ttk, messagebox
import threading
import schedule
import os
from datetime import datetime

# 设置 tesseract 路径（根据你的安装路径修改）
pytesseract.pytesseract.tesseract_cmd = r'H:\Tesseract-OCR\tesseract.exe'

# ==================== 配置 ====================
SAVE_DIR = "results"
os.makedirs(SAVE_DIR, exist_ok=True)
RESULT_FILE = os.path.join(SAVE_DIR, "numbers.csv")

# 全局变量
target_region_1 = None  # (x, y, w, h) 数字1
target_region_2 = None  # 数字2
window_title = ""
target_number_1 = ""
target_number_2 = ""
is_monitoring = False
capture_thread = None

# ==================== 图像捕获（支持最小化窗口） ====================
def capture_window_advanced(window_title):
    """使用 PrintWindow 捕获窗口（即使最小化也能获取缓存图像）"""
    # hwnd = win32gui.FindWindow(None, window_title)
    # hwnd = gw.getWindowsWithTitle(window_title)
    hwnd = find_window_fuzzy(window_title)
    if not hwnd:
        print(f"❌ 窗口 '{window_title}' 未找到！")
        return None

    # 获取窗口矩形
    left, top, right, bottom = win32gui.GetWindowRect(hwnd)
    width = right - left
    height = bottom - top

    # 创建设备上下文
    hwnd_dc = win32gui.GetWindowDC(hwnd)
    mfc_dc = win32ui.CreateDCFromHandle(hwnd_dc)
    save_dc = mfc_dc.CreateCompatibleDC()

    # 创建位图
    save_bitmap = win32ui.CreateBitmap()
    save_bitmap.CreateCompatibleBitmap(mfc_dc, width, height)
    save_dc.SelectObject(save_bitmap)

    # 使用 PrintWindow 抓图（关键：支持后台/最小化）
    result = ctypes.windll.user32.PrintWindow(hwnd, save_dc.GetSafeHdc(), 0x00000002)  # PW_CLIENTONLY
    if result == 0:
        print("⚠️ PrintWindow 失败，尝试 BitBlt...")
        # 回退到 BitBlt
        save_dc.BitBlt((0, 0), (width, height), mfc_dc, (0, 0), win32con.SRCCOPY)

    # 转为 numpy
    signed_ints = save_bitmap.GetBitmapBits(True)
    img = np.frombuffer(signed_ints, dtype='uint8')
    img.shape = (height, width, 4)
    img = cv2.cvtColor(img, cv2.COLOR_BGRA2BGR)

    # 清理资源
    win32gui.DeleteObject(save_bitmap.GetHandle())
    save_dc.DeleteDC()
    mfc_dc.DeleteDC()
    win32gui.ReleaseDC(hwnd, hwnd_dc)

    return img

# ==================== OCR 定位数字区域 ====================
def find_number_region(img, target_text):
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    _, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
    data = pytesseract.image_to_data(thresh, config='--psm 6', output_type=pytesseract.Output.DICT)
    n_boxes = len(data['text'])

    for i in range(n_boxes):
        text = data['text'][i].strip()
        if target_text in text:
            x = data['left'][i]
            y = data['top'][i]
            w = data['width'][i]
            h = data['height'][i]
            return (x, y, w, h)
    return None

# ==================== 区域 OCR 识别 ====================
def ocr_region(img, region):
    x, y, w, h = region
    roi = img[y:y+h, x:x+w]
    gray = cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY)
    _, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
    config = '--psm 8 -c tessedit_char_whitelist=0123456789'
    text = pytesseract.image_to_string(thresh, config=config).strip()
    return text

# ==================== 保存结果 ====================
def save_result(text1, text2):
    now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    with open(RESULT_FILE, 'a', encoding='utf-8') as f:
        if os.path.getsize(RESULT_FILE) == 0:
            f.write("Time,Value1,Value2\n")
        f.write(f"{now},{text1},{text2}\n")
    print(f"[{now}] 识别结果: {text1} | {text2}")

# ==================== 定时任务 ====================
def monitoring_job():
    global target_region_1, target_region_2, window_title
    if not target_region_1 and not target_region_2:
        return

    img = capture_window_advanced(window_title)
    if img is None:
        print("📷 截图失败")
        return

    text1 = text2 = "N/A"
    if target_region_1:
        text1 = ocr_region(img, target_region_1)
    if target_region_2:
        text2 = ocr_region(img, target_region_2)

    save_result(text1, text2)

# ==================== 监控线程 ====================
def start_monitoring():
    global is_monitoring
    schedule.every(5).minutes.do(monitoring_job)
    while is_monitoring:
        schedule.run_pending()
        time.sleep(1)

# ==================== GUI 主界面 ====================
class MonitorApp:
    def __init__(self, root):
        self.root = root
        self.root.title("窗口数字监控器 v1.0")
        self.root.geometry("500x400")
        self.root.resizable(False, False)

        self.create_widgets()

    def create_widgets(self):
        frame = ttk.Frame(self.root, padding="10")
        frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))

        # 窗口标题
        ttk.Label(frame, text="目标窗口标题:").grid(row=0, column=0, sticky=tk.W, pady=5)
        self.entry_title = ttk.Entry(frame, width=40)
        self.entry_title.grid(row=0, column=1, pady=5)

        # 数字1
        ttk.Label(frame, text="数字目标 1:").grid(row=1, column=0, sticky=tk.W, pady=5)
        self.entry_num1 = ttk.Entry(frame, width=40)
        self.entry_num1.grid(row=1, column=1, pady=5)

        # 数字2
        ttk.Label(frame, text="数字目标 2:").grid(row=2, column=0, sticky=tk.W, pady=5)
        self.entry_num2 = ttk.Entry(frame, width=40)
        self.entry_num2.grid(row=2, column=1, pady=5)

        # 按钮
        btn_frame = ttk.Frame(frame)
        btn_frame.grid(row=3, column=0, columnspan=2, pady=10)

        ttk.Button(btn_frame, text="开始监控", command=self.start).pack(side=tk.LEFT, padx=5)
        ttk.Button(btn_frame, text="停止监控", command=self.stop).pack(side=tk.LEFT, padx=5)
        ttk.Button(btn_frame, text="立即识别一次", command=self.quick_ocr).pack(side=tk.LEFT, padx=5)

        # 状态框
        ttk.Label(frame, text="状态信息:").grid(row=4, column=0, sticky=tk.W, pady=5)
        self.text_log = tk.Text(frame, height=10, width=60)
        self.text_log.grid(row=5, column=0, columnspan=2, pady=5)
        self.text_log.insert(tk.END, "👉 输入窗口标题和数字，点击【开始监控】\n")

        # 滚动条
        scrollbar = ttk.Scrollbar(frame, orient=tk.VERTICAL, command=self.text_log.yview)
        scrollbar.grid(row=5, column=2, sticky='ns')
        self.text_log['yscrollcommand'] = scrollbar.set

    def log(self, msg):
        self.text_log.insert(tk.END, msg + "\n")
        self.text_log.see(tk.END)

    def start(self):
        global window_title, target_number_1, target_number_2, is_monitoring, capture_thread
        window_title = self.entry_title.get().strip()
        target_number_1 = self.entry_num1.get().strip()
        target_number_2 = self.entry_num2.get().strip()

        if not window_title:
            messagebox.showwarning("警告", "请输入窗口标题！")
            return

        if not target_number_1 and not target_number_2:
            messagebox.showwarning("警告", "至少输入一个识别数字！")
            return

        self.log(f"🔍 正在查找窗口: {window_title}")
        img = capture_window_advanced(window_title)
        if img is None:
            messagebox.showerror("错误", "无法找到或截图该窗口！")
            return

        global target_region_1, target_region_2
        if target_number_1:
            region1 = find_number_region(img, target_number_1)
            if region1:
                target_region_1 = region1
                self.log(f"✅ 找到数字 '{target_number_1}' 区域: {region1}")
            else:
                self.log(f"❌ 未找到数字 '{target_number_1}'")

        if target_number_2:
            region2 = find_number_region(img, target_number_2)
            if region2:
                target_region_2 = region2
                self.log(f"✅ 找到数字 '{target_number_2}' 区域: {region2}")
            else:
                self.log(f"❌ 未找到数字 '{target_number_2}'")

        if not target_region_1 and not target_region_2:
            messagebox.showerror("错误", "未能定位任何数字区域！")
            return

        is_monitoring = True
        capture_thread = threading.Thread(target=start_monitoring, daemon=True)
        capture_thread.start()
        self.log("🟢 监控已启动，每5分钟识别一次...")

    def stop(self):
        global is_monitoring
        is_monitoring = False
        self.log("🔴 监控已停止")

    def quick_ocr(self):
        global target_region_1, target_region_2, window_title
        if not window_title:
            messagebox.showwarning("警告", "请先点击【开始监控】以初始化参数")
            return

        img = capture_window_advanced(window_title)
        if img is None:
            self.log("📷 截图失败")
            return

        text1 = text2 = "N/A"
        if target_region_1:
            text1 = ocr_region(img, target_region_1)
        if target_region_2:
            text2 = ocr_region(img, target_region_2)

        self.log(f"📌 快速识别: {text1} | {text2}")

def find_window_fuzzy(partial_title):
    results = []
    def callback(hwnd, _):
        if win32gui.IsWindowVisible(hwnd):
            if partial_title.lower() in win32gui.GetWindowText(hwnd).lower():
                results.append(hwnd)
        return True
    win32gui.EnumWindows(callback, None)
    return results[0] if results else None

# ==================== 主程序 ====================
def main():
    root = tk.Tk()
    app = MonitorApp(root)
    root.mainloop()

if __name__ == "__main__":
    main()